#include "js-functions.h"
#include <glib.h>

static JSBool print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
static JSBool setInterval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
static JSBool clearInterval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
static js_engine *engine = NULL;

struct JSFunctionSpec global_funcs[] = {
    {"print", print, 0, 0, 0},
    {"setInterval", setInterval, 2, 0, 0},
    {"clearInterval", clearInterval, 1, 0, 0},
};

void js_engine_define_functions(js_engine *new)
{
    engine = new;
    JS_DefineFunctions(engine->cx, engine->glob, global_funcs);
}

static JSBool
print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    uintN i, n;
    JSString *str;

    for (i = n = 0; i < argc; i++) {
        str = JS_ValueToString(cx, argv[i]);
        if (!str)
            return JS_FALSE;
        g_print("%s%s", i ? " " : "", JS_GetStringBytes(str));
    }
    n++;
    if (n)
        g_print("\n");
    return JS_TRUE;
}

static void dispatchJSScript(gpointer ptr)
{
    JSScript *script = (JSScript *)ptr;
    jsval rval;
    if(JS_ExecuteScript(engine->cx, engine->glob, script, &rval) == JS_FALSE)
	g_message("Script failed.");
}

static JSBool setInterval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    guint interval_msec = 0;
    guint thread_id = 0;
    GString *cmd = NULL;
    JSScript *script = NULL;
	
    if(argc != 2){
	g_error("Arguments required.");
	return JS_FALSE;
    }
    if(!JSVAL_IS_STRING(argv[0])){
	g_warning("Argument 1 is not a string.");
	return JS_FALSE;
    }
    if(!JSVAL_IS_INT(argv[1])){
	g_warning("Argument 2 is not a integer.");
	return JS_FALSE;
    }
	
    cmd = g_string_new("this.");
    g_string_append(cmd, JS_GetStringBytes(JSVAL_TO_STRING(argv[0])));
    g_string_append(cmd,";");

    interval_msec = JSVAL_TO_INT(argv[1]);
	
    script = JS_CompileScript(cx, obj, cmd->str, cmd->len, NULL, 0);
    g_message("setInterval %s %d: thread id: %d",cmd->str,interval_msec,thread_id);
    g_string_free(cmd,TRUE);
    g_return_val_if_fail(script, JS_FALSE);

    thread_id = g_timeout_add(interval_msec, (gpointer)dispatchJSScript, script);
    *rval = INT_TO_JSVAL(thread_id);
    return JS_TRUE;
}

static JSBool clearInterval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    if(argc != 1){
	g_error("Arguments error.");
	return JS_FALSE;
    }
    if(JSVAL_IS_INT(argv[0])){
	GSource *thread_src;
	guint thread_id = JSVAL_TO_INT(argv[0]);
	thread_src = g_main_context_find_source_by_id(NULL, thread_id);
	g_source_destroy(thread_src);
	g_message("clearInterval thread id: %d",thread_id);
	return JS_TRUE;
    }else{
	g_error("Argument is not a integer.");
	return JS_FALSE;
    }
}
